/****************************************************************************
 **
 ** This file is part of the yFiles extension package GraphML-3.2-yFiles-2.7.
 ** 
 ** yWorks proprietary/confidential. Use is subject to license terms.
 **
 ** Redistribution of this file or of an unauthorized byte-code version
 ** of this file is strictly forbidden.
 **
 ** Copyright (c) 2000-2009 by yWorks GmbH, Vor dem Kreuzberg 28, 
 ** 72070 Tuebingen, Germany. All rights reserved.
 **
 ***************************************************************************/

package demo.yext.graphml;

import y.base.DataMap;
import y.base.Graph;
import y.base.Node;
import y.base.NodeMap;
import y.option.OptionHandler;
import y.util.Maps;
import y.view.EditMode;
import y.view.PopupMode;
import y.view.ViewMode;
import y.view.HitInfo;
import yext.graphml.graph2D.GraphMLIOHandler;

import javax.swing.AbstractAction;
import javax.swing.JMenu;
import javax.swing.JPopupMenu;
import java.awt.event.ActionEvent;
import java.util.HashMap;
import java.util.StringTokenizer;

/**
 * This demo shows how to configure GraphMLIOHandler to be able to handle
 * extra node and graph data of complex type.
 * Additional data for a node and edge can be edited by right-clicking on the corresponding
 * element. To edit the graph data, right-click on the canvas background.
 * The element tooltip will show the currently set data values for each element.
 */
public class ComplexExtensionGraphMLDemo extends GraphMLDemo {

  /**
   * Stores a newline-separated string for each node that is interpreted as
   * a list of items. The GraphML representation of this String will have the
   * structured form
   * <ItemList>
   *   <Item>  </Item>
   *   <Item>  </Item>
   *   ...
   * </ItemList>
   */
  NodeMap nodeDataMap;

  /**
   * Stores a String value for the graph using a custom serialization mechanism
   */
  DataMap graphDataMap;


  public ComplexExtensionGraphMLDemo() {

    //define a view mode that displays the currently set data values
    ViewMode tooltipMode = new ViewMode() {
      public void mouseMoved(double x, double y) {
        HitInfo info = getHitInfo(x,y);
        if (info.getHitNode() != null) {
          String items = (String) nodeDataMap.get(info.getHitNode());
          if(items != null) {
            StringTokenizer tok = new StringTokenizer(items, "\n\r");
            String tipText = "<html>Node Items:<table>";
            while (tok.hasMoreTokens())
              tipText += "</tr></td>" + tok.nextToken() + "</td></tr>";
            tipText += "</table>";
            view.setToolTipText(tipText);
          }
        }
        else {
          view.setToolTipText("MyGraphAttribute=" + graphDataMap.get(view.getGraph2D()));
        }
      }
    };

    //add the view mode to the view
    view.addViewMode(tooltipMode);
  }

  /**
   * Create a GraphMLIOHandler that reads and writes additional node and graph data
   * of complex type.
   */
  protected GraphMLIOHandler createGraphMLIOHandler() {

    nodeDataMap = view.getGraph2D().createNodeMap();
    graphDataMap = Maps.createDataMap(new HashMap());

    GraphMLIOHandler ioHandler = new ComplexExtensionGraphMLIOHandler(nodeDataMap, graphDataMap);

    return ioHandler;
  }

  /**
   * Create an edit mode that displays a context-sensitive popup-menu when right-clicking
   * on an the canvas.
   */
  protected EditMode createEditMode() {
    EditMode editMode = super.createEditMode();

    editMode.setPopupMode(new PopupMode() {
      public JPopupMenu getNodePopup(Node v) {
        JPopupMenu pm = new JPopupMenu();
        pm.add(new EditAttributeAction("Edit Node Attribute...", v, nodeDataMap));
        return pm;
      }

      public JPopupMenu getPaperPopup(double x, double y) {
        JPopupMenu pm = new JPopupMenu();
        pm.add(new EditAttributeAction("Edit Graph Attribute...", getGraph2D(), graphDataMap));
        return pm;
      }
    });

    return editMode;
  }


  /**
   * Editor action for the additional node, edge and graph attributes.
   */
  static class EditAttributeAction extends AbstractAction {
    private Object object;
    private DataMap dataMap;

    private OptionHandler op;

    EditAttributeAction(String name, Object object, DataMap dataMap) {
      super(name);
      this.object = object;
      this.dataMap = dataMap;
      op = new OptionHandler(name);
      if (object instanceof Node) {
        op.addString("Node Items", (String)dataMap.get(object), 10);
      } else if (object instanceof Graph) {
        op.addString("MyGraphAttribute", (String)dataMap.get(object));
      }
    }

    public void actionPerformed(ActionEvent actionEvent) {
      if (op.showEditor()) {
        if (object instanceof Node) {
          dataMap.set(object, op.getString("Node Items"));
        } else if(object instanceof Graph) {
          dataMap.set(object, op.getString("MyGraphAttribute"));
        }
      }
    }
  }


  /**
   * Add sample graphs to the menu.
   */
  protected JMenu createSampleGraphMenu() {
    return createSampleGraphMenu(new String[]{"resources/custom/complexdemo.graphml"});
  }

  /**
   * Launches this demo.
   */
  public static void main(String[] args) {
    initLnF();
    final ComplexExtensionGraphMLDemo demo = new ComplexExtensionGraphMLDemo();
    demo.start();
  }
}
